package com.itheima.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 记录日志的工具类。他里面提供了公共的代码
 */
@Component("logger")
@Aspect
public class Logger {

    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    private  void pt1(){}
    /**
     * 前置通知
     */
//    @Before("pt1()")
    public void beforePrintLog(){
        System.out.println("前置通知:Logger类中的beforePrintLog方法开始记录日志");
    }

    /**
     * 后置通知
     */
//    @AfterReturning("pt1()")
    public void afterReturningPrintLog(){
        System.out.println("后置通知:Logger类中的afterReturningPrintLog方法开始记录日志");
    }
    /**
     * 异常通知
     */
//    @AfterThrowing("pt1()")
    public void afterThrowingPrintLog(){
        System.out.println("异常通知:Logger类中的afterThrowingPrintLog方法开始记录日志");
    }
    /**
     * 最终通知
     */
//    @After("pt1()")
    public void afterPrintLog(){
        System.out.println("最终通知:Logger类中的afterPrintLog方法开始记录日志");
    }
    /**
     * 环绕通知
     * 配置了环绕通知,切入点方法没有执行,通知方法执行了
     * 分析:
     *      通过对比动态代理的环绕通知代码.动态代理中有明确的方法调用,而配置代码中没有
     *  解决：
     *      Spring框架为我们提供了一个接口，ProceedingJoinPoint,该接口有一个方法proceed()。此方法相当于明确调用切入点方法
     *      该接口可以作为环绕通知的方法参数，在程序执行时，spring框架会为我们提供该接口的实现类使用
     *
     * spring中的环绕通知：
     *      他是spring框架为我们提供的一种可以在代码中手动控制增强方法由何时执行的方式
     */
    @Around("pt1()")
    public Object aroundPrintLog(ProceedingJoinPoint pjp){
        Object rtValue;
        try {
            Object[] args = pjp.getArgs();//得到方法执行所需的参数
            System.out.println(" Logger类中的aroundPrintLog方法开始记录日志--前置");

            rtValue = pjp.proceed();//明确调用业务方法（切入点）
            System.out.println(" Logger类中的aroundPrintLog方法开始记录日志--后置");

            return rtValue;

        }
        catch (Throwable t ){
            System.out.println(" Logger类中的aroundPrintLog方法开始记录日志--异常");

            throw  new RuntimeException(t);
        }finally {
            System.out.println(" Logger类中的aroundPrintLog方法开始记录日志--最终");

        }

    }


}
